package hello

import (
	"appengine"
	"appengine/datastore"
	"appengine/blobstore"
)

type Recipe struct {
	CategoryId int64
	Name string
	Code string
	Id int64
	Description []byte
	Display bool
	Image appengine.BlobKey
	Thumb appengine.BlobKey
	// convenient transient placeholder for ingredients to render
	Ingredients []*Ingredient `datastore:"-"`
	// indicates that recipe has more ingredients that are in 'Ingredients' arr.
	// is used in template 'recipes.html'
	HasMoreIngredients bool `datastore:"-"`
}

func createRecipeKey(c *appengine.Context) (key *datastore.Key) {
	key = datastore.NewIncompleteKey(*c, "Recipe", nil)
	return
}

func restoreRecipeKey(c *appengine.Context, id int64) (key *datastore.Key) {
	key = datastore.NewKey(*c, "Recipe", "", id, nil)
	return
}

func listAllRecipes(c *appengine.Context, filterVisible bool) []*Recipe {
	q := datastore.NewQuery("Recipe")
	if filterVisible {
		q = q.Filter("Display =", true)
	}
	recipes := make([]*Recipe, 0)
	_, err := q.GetAll(*c, &recipes)
	panicIfErr(err)
	return recipes
}

func listRandomRecipes(c *appengine.Context, count int) []*Recipe {
	q := datastore.NewQuery("Recipe").Limit(count)
	recipes := make([]*Recipe, 0)
	_, err := q.GetAll(*c, &recipes)
	panicIfErr(err)
	return recipes
}

func listRecipesByCategory(c *appengine.Context, categoryId int64) []*Recipe {
	q := datastore.NewQuery("Recipe").Filter("CategoryId =", categoryId)
	recipes := make([]*Recipe, 0)
	_, err := q.GetAll(*c, &recipes)
	panicIfErr(err)
	return recipes
}

func saveRecipe(c *appengine.Context, recipe *Recipe) (key *datastore.Key, err error) {
	key, err = datastore.Put(*c, createRecipeKey(c), recipe)
	panicIfErr(err)
	recipe.Id = key.IntID()
	if len(recipe.Code) == 0 {
		recipe.Code = translit(recipe.Name)
	}
	key, err = datastore.Put(*c, key, recipe)
	panicIfErr(err)
	return
}

func getRecipe(c *appengine.Context, id int64) (recipe *Recipe, err error) {
	recipe = new(Recipe)
	err = datastore.Get(*c, restoreRecipeKey(c, id), recipe)
	return
}

func getRecipeByCode(c *appengine.Context, code string) (*Recipe) {
	recipes := make([]Recipe, 0)
	_, err := datastore.NewQuery("Recipe").Filter("Code =", code).Limit(1).GetAll(*c, &recipes)
	panicIfErr(err)
	var recipe Recipe
	if len(recipes) > 0 {
		recipe = recipes[0]
		return &recipe
	} else {
		panic(datastore.ErrNoSuchEntity)
	}
	return &recipe
}

func updateRecipe(c *appengine.Context, id int64, recipe *Recipe) (key *datastore.Key) {
	// get old recipe
	oldRecipe := new(Recipe)
	err := datastore.Get(*c, restoreRecipeKey(c, id), oldRecipe)
	panicIfErr(err)
	
	deleteOldImage(c, recipe.Image, oldRecipe.Image)
	deleteOldImage(c, recipe.Thumb, oldRecipe.Thumb)
	
	// preserve old image/thumb if no new provided
	if len(recipe.Image) == 0 {
		recipe.Image = oldRecipe.Image
	}
	if len(recipe.Thumb) == 0 {
		recipe.Thumb = oldRecipe.Thumb
	}

	recipe.Id = id
	if len(recipe.Code) == 0 {
		recipe.Code = translit(recipe.Name)
	}
	key, err = datastore.Put(*c, restoreRecipeKey(c, id), recipe)
	panicIfErr(err)
	return
}

func deleteOldImage(c *appengine.Context, newImage appengine.BlobKey, oldImage appengine.BlobKey) {
	if len(newImage) != 0 && len(oldImage) != 0 {
		// delete old image
		err := blobstore.Delete(*c, oldImage)
		panicIfErr(err)
	}
}

func deleteRecipe(c *appengine.Context, id int64) {
	err := datastore.Delete(*c, restoreRecipeKey(c, id))
	panicIfErr(err)
	// get and delete ingredients
	q := datastore.NewQuery("Ingredient").KeysOnly().Filter("RecipeId =", id)
	ingredientKeys, err := q.GetAll(*c, nil)
	panicIfErr(err)
	datastore.DeleteMulti(*c, ingredientKeys)	
}